#ifndef _AKTIONSMANAGER_CPP_
#define _AKTIONSMANAGER_CPP_
#include <gtk/gtk.h>
#include "feld.h"
#include "state.h"
#include "aktionsmanager.h"
#include <time.h>
#include <glibmm.h>
bool Aktionsmanager::isRunning()
{
        bool tmp;
        tmp = this->mutex->trylock(); // gibt flase zurÃ¼ck, wenn mutex belegt ist, sonst true und belegt mutex
        if(tmp) this->mutex->unlock(); //wenn mutex belegt wurde, mutex freigeben
        return !tmp;    //wenn tmp false ist, ist mutex belegt -> RÃ¼ckgabewert ist gegenteil von tmp
}

 void Aktionsmanager::doshowfield(){
        //g_print("swap buffers\r\n");
        drawingmutex->lock();
        feld->copyFieldToViewer();
        //g_print("DRAW\r\n");
        // hier muss setGen(feld->getgen()) hin!!!!!!!!!!!!!!!!!!!
        //feld->doDrawField();
        (*m_dispatcher)(); 
        
        };
        
void Aktionsmanager::run()
{
        state aktZustand;
       
        //Mutex holen, wenn gesperrt warten
        this->mutex->lock();
       //g_print("action am start\r\n");
       /*if (regelwerk){
       g_print("rules: ");
       for(int i=0;i<8;i++){if (regelwerk->getRule(true, i))g_print("%i",i); ;}
       g_print("/");
       for(int i=0;i<8;i++){if (regelwerk->getRule(false, i))g_print("%i",i); ;}
       g_print("\r\n");};*/
       //g_print("viewer %i\r\n",viewer);
        //zustand holen und abarbeiten
        aktZustand = zustand->getState();
        while((aktZustand != done) and (aktZustand != stop)) //fragt nach aufgaben, bis keine aufgabe mehr vorhanden -> beendet sich dann
        {
                switch(aktZustand)
                {
                        case running:                   doRunning();
                                                                        break;
                        case singleStep:                doSingleStep();
                                                                        break;
                        case save:                              doSave();
                                                                        break;
                        case load:                              doLoad();
                                                                        break;
                        case randomini:                    doRandom();
                                                                        break;  
                        case setCell:                   doSetCell();
                                                                        break;
                        case setHeightWidth:    doSetHeightWidth();
                                                                        break;
                        case changeRule:                doChangeRule();
                                                                        break;
                        default:                                                                
                ;};
                aktZustand = zustand->getState();//sonst dauerschleife^^
        };
		
        //Mutex freigeben
        this->mutex->unlock();
}

Aktionsmanager::Aktionsmanager(Feld *f,Regelwerk *r, Viewer *v, Zustand *z, Dateimanager *d,Gtk::Label *gen,Glib::Mutex * dmutex,Glib::Dispatcher *m_dis,Glib::Dispatcher *s_dis,Glib::Dispatcher *z_dis)
{        m_dispatcher=m_dis;
        s_dispatcher=s_dis;
        z_dispatcher=z_dis;
        drawingmutex=dmutex;
        this->generation=gen;
        this->mutex = new Glib::Mutex();
        this->regelwerk=r;
        this->viewer=v;
        this->zustand=z;
        this->dateimanager=d;
        this->feld= f;
        feld->setZustand(zustand);
        feld->setViewer(viewer);
        feld->setRegelwerk(r);
        //init feld schnell mal
        feld->setHeightWidth(HeightWidth(80,60));
        //g_print("constructor fertig\r\n");
        //this->running=0;
}

Aktionsmanager::~Aktionsmanager() 
{
        delete this->feld;
				delete this->mutex;
}


void Aktionsmanager::doRunning()
{
        Glib::Timer     m_timer;//m_timer2;
        unsigned long microsec;//microsec2;
        long secs;//secs2;
		int aktuelle_gen=feld->getGen();
        //Time Ticks holen
         m_timer.start();
        //parameter holen und wartezeit berechnen
		int skipping=zustand->getSkip();
        //Feld in nÃ¤chste Generation
        
       /* m_timer2.start();
        secs2 = (long)m_timer2.elapsed(microsec2);
        microsec2=(long)((microsec2+500)/1000)+(secs2 * 1000);
        //g_print("calc time %li \r\n",microsec2);*/
        for(int i=0;i<=skipping;i++){
        this->feld->nextGen();}
        
        //feld malen , wenn es zu einer berechnung kam, auch wenn abgebrochen wurde:
        if (feld->getGen()!= aktuelle_gen){    
        doshowfield();};

        //g_print("nextgen<<<<<<<\r\n");
        //g_thread_yield();
        //Glib::usleep(50000);
        //Zeitdiff abwarten
		secs = (long)m_timer.elapsed(microsec);
        microsec=(long)((microsec+500)/1000)+1000*secs; // dieser schritt rechnet die micro in milisecs um
		//warteschleife
		
        while(microsec < (unsigned int)(zustand->getSpeed()) and secs<=2)	
        {
        //g_thread_yield();
        secs = (long)m_timer.elapsed(microsec);
        microsec=(long)((microsec+500)/1000)+(secs * 1000);
        if(this->zustand->getState()==stop) {g_print("Simulation/Einzelschritt fertig/gestoppt \r\n");return;}
        if (microsec>=10)Glib::usleep(microsec-10);
        //überlauf findet nicht statt mit glib!!!yeah!!!
        //if(cl2<cl1) return;     //ZÃ¤hlerÃ¼berlauf abfangen
		//if(this->zustand->getState()==stop) return;		//zusÃ¤tzliches prÃ¼fen des Zustandes, um Abbruch bei extrem langsamen geschw zu erlauben
        }
        

		
		
        //real=(int)real;
        //if (real +1>= zustand->getSpeed())
        this->zustand->setRealSpeed(microsec);
        
        //g_print("speed %i\r\n",zustand->getSpeed());
        return;
}

void Aktionsmanager::doSingleStep()
{
        int count;
        // Anzahl holen
        count = this->zustand->getAnzahl();
        //Feld in nÃ¤chste Generation umwandeln lassen
        if (count==1){zustand->setSpeed(1);};//im letzen schritt geschwindigkeit auf 1 setzen, damit nutzer nicht warten muss, bis zeit abgelaufen ist
        if(count>0){doRunning();};
        count--;
        this->zustand->setAnzahl(count);
        //Status auf "Done" setzen wenn Schrittzahl 0
        if(count<=0) {this->zustand->setState(done);zustand->setSpeed(1);};
        return;
}

void Aktionsmanager::doSave()
{
        string pfad;
        string descr;
        string datum;
        //Parameter Pfad holen
        pfad = this->zustand->getPfad();
        //Parameter Beschreibung holen
        descr = this->zustand->getDescr();
        //Zeit holen
        time_t seconds;
        seconds = time(NULL); // liefert sekunden seit 1. Januar 1970  
       
        if(seconds!=-1)
                datum = ctime(&seconds); //liefert Ortszeit aus sekunden seit 1. Januar 1970 als string zurÃ¼ck, wird in Obejekt(!) string gespeichert
        else
                datum = "00.00.0000";     //wenn time aus irgend einem grund keinen wert zurÃ¼ckgegeben hat, wird das Datum auch nichts gesetzt
               
        //Dateimanager zum speichern anweisen
        this->dateimanager->save( pfad,descr,datum,*(this->feld),this->regelwerk);
        //Status auf Done setzen
        (*s_dispatcher)();
        this->zustand->setState(done);
}


void Aktionsmanager::doLoad()
{
        string pfad;
        //Parameter Pfad holen
        pfad = this->zustand->getPfad();
        //altes Feld lÃ¶schen
        //delete this->feld;
        //neues Feld erzeugen
        //this->feld = new Feld(); 
        //Dateimanager zum laden anweisen
        this->dateimanager->load(pfad, *(this->feld),this->regelwerk);
        //regelwerk neu setzen
        //delete this->regelwerk;
        //this->regelwerk = this->feld->getRegelwerk();
        (*z_dispatcher)();
        //feld malen
        doshowfield();
        
        //Status auf done setzen
        this->zustand->setState(done);
}

void Aktionsmanager::doRandom()
{
        int random;
        bool tmp;
        //HeightWidth hw;
        //Parameter
        
        HeightWidth pos;
        pos = this->zustand->getMasse();
        g_print("Fordert Speicherplatz an\r\n");
        this->feld->setHeightWidth(pos);
        int wkt = (int)((float)(this->zustand->getRand())*(100));
        srand ( time(NULL) );
        //FeldgrÃ¶Ãe holen
        int height = this->feld->getHeight();
        int width = this->feld->getWidth();
       g_print("Erzeugt zufaelliges Feld der Groesse: %i, %i\r\n",height,width);
        for (int ii=0;ii<height;ii++)
                for(int jj=0; jj<width; jj++)
                {
                        random=rand()%100;
                        tmp = (random < wkt);
                         //g_print("do random stuff: %i, %i\r\n",ii,jj);
                        this->feld->setCell(HeightWidth(ii,jj), tmp);
                };     
        //feld malen
        //g_print("feld fertig erzeugt\r\n");
        feld->setGen(0);
        (*z_dispatcher)();
        doshowfield();
        //status auf done
        
        this->zustand->setState(done);
}

void Aktionsmanager::doSetCell()
{
        HeightWidth pos;
        //Parameter holen
        pos = this->zustand->getPosition();
        //Feld anweisen die Zelle zu inveriteren!
        this->feld->invertCell(pos);
        //status auf done setzen
        this->zustand->setState(done);
}

void Aktionsmanager::doSetHeightWidth()
{          //g_print("sethighwidth");
        HeightWidth pos;
        //Parameter holen
        pos = this->zustand->getMasse();
        //altes Feld lÃ¶schen
        //delete this->feld;
        //neues Feld erzeugen
        //this->feld = new Feld();        
        //HÃ¶he und Breite setzen lassen
        this->feld->setHeightWidth(pos);
        //Zustand auf done
        zustand->setState(done);
        //g_print("sethighwidth ende\r\n");
}

void Aktionsmanager::doChangeRule()
{
        if(this->feld->getGen()>=0)       //nur dann das Regelwerk Ã¤ndern, wenn das Feld in Generation 0 ist!
        {
                for(int i=0; i<2; i++)
                {
                        for(int j=0; j<9; j++)
                        {
                                this->regelwerk->setRule(i, j, this->zustand->getRule(i, j));   //regelwerk regel setzen, auf den Wert, der im Parameter in Zustand gespeichert ist
                        }
                }
        }else {g_print("dont work");};

zustand->setState(done);
}




#endif

